// #pragma once
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/time.h>
#include <malloc.h>
#include <sys/ioctl.h>
#include <time.h>
#include <linux/serial.h>

#include "blockQueue.hpp"

#include <pthread.h>
#include <unistd.h>
#include <ctime>

#define EM9280_IOCTL_SET_WAIT_TIME _IOR(242, 0x01, unsigned int)

typedef struct port_info
{
    int baud_rate;
    int port_fd;
    char parity;
    char stop_bit;
    char flow_ctrl;
    char data_bits;
} *pport_info;

// unsigned char XORCheck(unsigned char *pBuffer, unsigned int iLength)
// {
//     unsigned char b = 0;
//     for (int i = 0; i < iLength; i++)
//     {
//         b ^= pBuffer[i];
//     }
//     return b;
// }

int set_port_normal(int m_fd)
{
    struct termios new_opt;
    int status;
    // get the current config -> new_opt
    tcgetattr(m_fd, &new_opt);
    new_opt.c_cflag &= ~PARENB; /* Clear parity enable */
    new_opt.c_cflag &= ~CMSPAR; /* Clear parity enable */
    new_opt.c_iflag &= ~INPCK;  /* Disable parity checking */
    // tcflush(m_fd, TCIOFLUSH);
    /* status = tcsetattr(m_fd,TCSADRAIN,&new_opt); */
    status = tcsetattr(m_fd, TCSANOW, &new_opt); // tcsetattr 函数用于设置终端的各种属性，如波特率、数据位、停止位、校验位等。通过传递 TCSANOW 标志，函数将立即应用新的属性设置
    if (status != 0)
    {
        printf("Cannot set the serial bit8");
        return -1;
    }
    printf("setbit8 new_opt.c_cflag %x c_iflag %x\n", new_opt.c_cflag, new_opt.c_iflag);
    return status;
}

int set_port_bit8(int m_fd)
{
    struct termios new_opt;
    int status;
    // get the current config -> new_opt
    tcgetattr(m_fd, &new_opt);
    new_opt.c_cflag |= (PARENB | CMSPAR);
    new_opt.c_cflag &= ~PARODD;
    new_opt.c_iflag |= INPCK;
    status = tcsetattr(m_fd, TCSANOW, &new_opt);
    if (status != 0)
    {
        //		perror("Cannot set the serial bit8");
        return -1;
    }
    //    printf("setbit8 new_opt.c_cflag %x c_iflag %x\n",new_opt.c_cflag, new_opt.c_iflag);
    return status;
}

int set_port_bit9(int m_fd)
{
    struct termios new_opt;
    int status;
    // get the current config -> new_opt
    tcgetattr(m_fd, &new_opt);
    //   new_opt.c_cflag |= PARENB | CMSPAR |PARODD;
    new_opt.c_cflag |= PARENB | CS8 | CMSPAR | PARODD;
    new_opt.c_iflag |= INPCK;
    status = tcsetattr(m_fd, TCSANOW, &new_opt);
    if (status != 0)
    {
        //		perror("Cannot set the serial bit9");
        return -1;
    }
    //    printf("setbit9 new_opt.c_cflag %x c_iflag %x\n",new_opt.c_cflag,new_opt.c_iflag);

    return status;
}

int WritePort(char *Buf, int len, int m_fd)
{
    int sendlen = 0;

    sendlen = write(m_fd, Buf, len);

    if (sendlen == len)
    {
        return sendlen;
    }
    else
    {
        // 脠莽鹿没鲁枚脧脰脪莽鲁枚脟茅驴枚
        tcflush(m_fd, TCOFLUSH);
        return -1;
    }
}

int openport(char *Dev)
{
    int fd = open(Dev, O_RDWR | O_NOCTTY | O_NDELAY);
    if (-1 == fd)
    {
        perror("Can''t Open Serial Port");
        return -1;
    }
    else
    {
        printf("Open Serial %s Succeed!\n", Dev);
        return fd;
    }
}

int get_baud_rate(unsigned long int baud_rate)
{
    switch (baud_rate)
    {
    case 0:
        return B0;
    case 50:
        return B50;
    case 75:
        return B75;
    case 110:
        return B110;
    case 134:
        return B134;
    case 150:
        return B150;
    case 200:
        return B200;
    case 300:
        return B300;
    case 600:
        return B600;
    case 1200:
        return B1200;
    case 1800:
        return B1800;
    case 2400:
        return B2400;
    case 4800:
        return B4800;
    case 9600:
        return B9600;
    case 19200:
        return B19200;
    case 38400:
        return B38400;
    case 57600:
        return B57600;
    case 115200:
        return B115200;
    case 230400:
        return B230400;
    case 921600:
        return B921600;
    case 460800:
        return B460800;
    case 3000000:
        return B3000000;
    default:
        return -1;
    }
}

int set_port(pport_info p_info)
{
    struct termios new_opt;
    int baud_rate;
    int status, i;
    struct serial_struct ss, ss_set;

    // get the current config -> new_opt
    tcgetattr(p_info->port_fd, &new_opt);
    bzero(&new_opt, sizeof(new_opt));

    // convert baud rate -> baud_flag
    baud_rate = get_baud_rate(p_info->baud_rate);
    if (baud_rate == -1)
        baud_rate = B38400;

    tcflush(p_info->port_fd, TCIOFLUSH);
    // setup input/output baudrate
    cfsetispeed(&new_opt, baud_rate);
    //	LOG(emWarning, 0, 0, 0, "cfsetispeed::c_cflag = %x \r\n", new_opt.c_cflag);
    cfsetospeed(&new_opt, baud_rate);
    //	LOG(emWarning, 0, 0, 0, "cfsetospeed::c_cflag = %x\r\n", new_opt.c_cflag, baud_rate);
    status = tcsetattr(p_info->port_fd, TCSANOW, &new_opt);
    if (status != 0)
    {
        perror("tcsetattr::set baud rate failed\n");
        return -1;
    }

    /* set custom baud */
    if (get_baud_rate(p_info->baud_rate) == -1)
    {
        i = ioctl(p_info->port_fd, TIOCGSERIAL, &ss);
        if (i < 0)
        {
            //			LOG(emWarning, 0, 0, 0, "BAUD: error to get the serial_struct info:%s\n",strerror(errno));
            return -1;
        }
        //		LOG(emWarning, 0, 0, 0, "BAUD: org baud = %d,custom_divisor=%d,baud_base=%d\n",
        //        p_info->baud_rate,ss.custom_divisor,ss.baud_base);
        ss.flags = ASYNC_SPD_CUST;
        ss.custom_divisor = ss.baud_base / p_info->baud_rate;

        //		LOG(emWarning, 0, 0, 0, "ss.custom_divisor = %d \r\n",ss.custom_divisor);

        i = ioctl(p_info->port_fd, TIOCSSERIAL, &ss);
        if (i < 0)
        {
            //			LOG(emWarning, 0, 0, 0, "BAUD: error to set serial_struct:%s\n",strerror(errno));
            // return -2;
        }
        i = ioctl(p_info->port_fd, TIOCGSERIAL, &ss_set);
        //        LOG(emWarning, 0, 0, 0, "BAUD: success set baud to %d,custom_divisor=%d,baud_base=%d\n",
        //				p_info->baud_rate,ss_set.custom_divisor,ss_set.baud_base);
    }

    // 淇敼鎺у埗妯″紡锛屼繚璇佺▼搴忎笉浼氬崰鐢ㄤ覆鍙ｏ紵
    new_opt.c_cflag |= CLOCAL;
    // printf("c_cflag |= CLOCAL => %x\r\n", new_opt.c_cflag);

    // 淇敼鎺у埗妯″紡锛屼娇寰楄兘澶熶粠涓插彛璇诲彇杈撳叆鏁版嵁
    new_opt.c_cflag |= CREAD;
    // printf("c_cflag |= CREAD => %x\r\n", new_opt.c_cflag);

    new_opt.c_cflag |= HUPCL;
    // setup control flow
    switch (p_info->flow_ctrl)
    {
    case '0':
        // no control-flow
        new_opt.c_cflag &= ~CRTSCTS;
        break;
    case '1':
        // hardware control-flow
        new_opt.c_cflag |= CRTSCTS;
        //        LOG(emWarning, 0, 0, 0, "RTS\n");
        break;
    case '2':
        new_opt.c_iflag |= IXON | IXOFF | IXANY;
        break;
    }
    // printf("c_cflag(no ctl-flow) = %x\r\n", new_opt.c_cflag);

    // setup bit size
    new_opt.c_cflag &= ~CSIZE;
    switch (p_info->data_bits)
    {
    case '5':
        new_opt.c_cflag |= CS5;
        break;
    case '6':
        new_opt.c_cflag |= CS6;
        break;
    case '7':
        new_opt.c_cflag |= CS7;
        break;
    case '8':
        new_opt.c_cflag |= CS8;
        break;
    default:
        new_opt.c_cflag |= CS8;
    }
    //	LOG(emWarning, 0, 0, 0, "c_cflag |= CS8 => %x\r\n", new_opt.c_cflag);

    // setup parity
    switch (p_info->parity)
    {
    case 'n':
    case 'N':
        new_opt.c_cflag &= ~PARENB; /* Clear parity enable */
        new_opt.c_iflag &= ~INPCK;  /* Disable parity checking */
        break;

    case 'o':
    case 'O':
        new_opt.c_cflag |= (PARODD | PARENB); /* 璁剧疆涓哄鏁堥獙*/
        new_opt.c_iflag |= INPCK;             /* Enable parity checking */
        break;

    case 'e':
    case 'E':
        new_opt.c_cflag |= PARENB;  /* Enable parity */
        new_opt.c_cflag &= ~PARODD; /* 杞崲涓哄伓鏁堥獙*/
        new_opt.c_iflag |= INPCK;   /* Enable parity checking */
        break;

    case 'S':
    case 's': /*as no parity*/
        new_opt.c_cflag &= ~PARENB;
        new_opt.c_cflag &= ~CSTOPB;
        break;

    case 'M':
    case 'm': /*mark*/
        new_opt.c_cflag |= PARENB | CS8 | CMSPAR | PARODD;
        new_opt.c_iflag |= INPCK;
        break;

    case 'p':
    case 'P': /*space*/
        new_opt.c_cflag |= (PARENB | CMSPAR);
        new_opt.c_cflag &= ~PARODD;
        new_opt.c_iflag |= INPCK;
        break;

    default:
        fprintf(stderr, "Unsupported parity\n");
        return -1;
    }
    // printf("c_cflag &=~PARENB => %x\r\n", new_opt.c_cflag);

    // setup stop-bit
    if (p_info->stop_bit == '2')
    {
        new_opt.c_cflag |= CSTOPB;
        //        LOG(emWarning, 0, 0, 0, "p_info->stop_bit = %c\r\n", p_info->stop_bit);
    }
    else
    {
        new_opt.c_cflag &= ~CSTOPB;
    }
    // printf("c_cflag &=~CSTOPB => %x\r\n", new_opt.c_cflag);

    /* Set input parity option */
    if ((p_info->parity != 'n') || (p_info->parity != 'N'))
    {
        new_opt.c_iflag |= INPCK;
    }

    // 淇敼杈撳嚭妯″紡锛氬師濮嬫暟鎹緭鍑?raw 妯″紡)
    new_opt.c_lflag &= ~(ICANON | ECHO | ISIG); /*Input*/
    new_opt.c_oflag &= ~OPOST;                  /*Output*/

    // 淇敼鎺у埗瀛楃锛氳鍙栧瓧绗︾殑鏈€灏戜釜鏁颁负1 锛燂紵锛?
    new_opt.c_cc[VMIN] = 1;

    // 淇敼鎺у埗瀛楃锛氳鍙栫涓€涓瓧绗︾殑瓒呮椂鏃堕棿涓?脳100ms
    new_opt.c_cc[VTIME] = 1;

    // 璇曞浘鍘绘帀鍦ㄦ帴鏀舵椂蹇呴』鏀跺埌'\n'鎵嶈繑鍥炵殑闂
    // 蹇界暐杈撳叆鐨勫洖杞?
    // new_opt.c_iflag |= IGNCR;
    // new_opt.c_iflag &= ~(IXON|IXOFF|IXANY);

    // 濡傛灉鍙戠敓鏁版嵁婧㈠嚭锛屾帴鏀舵暟鎹紝浣嗘槸涓嶅啀璇诲彇
    tcflush(p_info->port_fd, TCIFLUSH);

    status = tcsetattr(p_info->port_fd, TCSANOW, &new_opt);
    if (status != 0)
    {
        perror("Cannot set the serial port parameters");
        return -1;
    }
    //    LOG(emWarning, 0, 0, 0, "setport new_opt.c_cflag %x c_iflag %X\n",new_opt.c_cflag, new_opt.c_iflag);
    return status;
}

int OpenPort(int PortNo, int baudrate, char databits, char stopbits, char parity, int m_fd)
{
    char portname[20];
    struct port_info info;
    pthread_attr_t attr;
    int res, wait_time = 0x06;

    sprintf(portname, "/dev/ttyS%d", PortNo);
    // sprintf( portname, "/dev/ttyUSB%d", PortNo );
    // sprintf( portname, "/dev/ttyISA%d", PortNo );
    if ((m_fd = open(portname, O_RDWR | O_NOCTTY | O_NONBLOCK)) == -1) // O_RDWR | O_NOCTTY | O_NDELAY |
    {
        perror("Cannot open the desired port");
        return -1;
    }
    //    m_iPortNo = PortNo;
    //
    // Fill in the device control block.
    //
    // 修改相关参数
    info.baud_rate = baudrate;
    info.parity = parity;
    info.data_bits = databits;
    info.flow_ctrl = '0';
    info.port_fd = m_fd;
    info.stop_bit = stopbits;

    if (set_port(&info) == -1)
    {
        printf("set port fail\n");
        return -1;
    }

    ioctl(m_fd, EM9280_IOCTL_SET_WAIT_TIME, wait_time);

    return m_fd;
}

int setport(int fd, int baud, int databits, int stopbits, int parity)
{
    int baudrate;
    struct termios newtio;
    switch (baud)
    {
    case 300:
        baudrate = B300;
        break;
    case 600:
        baudrate = B600;
        break;
    case 1200:
        baudrate = B1200;
        break;
    case 2400:
        baudrate = B2400;
        break;
    case 4800:
        baudrate = B4800;
        break;
    case 9600:
        baudrate = B9600;
        break;
    case 19200:
        baudrate = B19200;
        break;
    case 38400:
        baudrate = B38400;
        break;
        // case 51200:
        //  baudrate=B51200;
        //  break;
    case 115200:
        baudrate = B115200;
        break;
    case 500000:
        baudrate = B500000;
        break;
    case 1000000:
        baudrate = B1000000;
        break;
    default:
        baudrate = B9600;
        break;
    }
    tcgetattr(fd, &newtio);
    bzero(&newtio, sizeof(newtio));
    // setting   c_cflag
    newtio.c_cflag &= ~CSIZE;
    switch (databits) /*设置数据位数*/
    {
    case 7:
        newtio.c_cflag |= CS7; // 7位数据位
        break;
    case 8:
        newtio.c_cflag |= CS8; // 8位数据位
        break;
    default:
        newtio.c_cflag |= CS8;
        break;
    }
    switch (parity) // 设置校验
    {
    case 'n':
    case 'N':
        newtio.c_cflag &= ~PARENB; /* Clear parity enable */
        newtio.c_iflag &= ~INPCK;  /* Enable parity checking */
        break;
    case 'o':
    case 'O':
        newtio.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
        newtio.c_cflag &= ~CMSPAR;
        newtio.c_iflag |= INPCK; /* Disnable parity checking */
        break;
    case 'e':
    case 'E':
        newtio.c_cflag |= PARENB;             /* Enable parity */
        newtio.c_cflag &= ~(PARODD | CMSPAR); /* 转换为偶效验*/
        newtio.c_iflag |= INPCK;              /* Disnable parity checking */
        break;
    case 'M':
    case 'm': /*Mark: parity=1 */
        newtio.c_cflag |= (PARENB | CMSPAR | PARODD);
        newtio.c_iflag |= INPCK;
        break;
    case 'S':
    case 's': /*Space: parity=0;*/
        newtio.c_cflag |= (PARENB | CMSPAR);
        newtio.c_cflag &= ~PARODD;
        newtio.c_iflag |= INPCK;
        break;
    default:
        newtio.c_cflag &= ~PARENB; /* Clear parity enable */
        newtio.c_iflag &= ~INPCK;  /* Enable parity checking */
        break;
    }
    switch (stopbits) // 设置停止位
    {
    case 1:
        newtio.c_cflag &= ~CSTOPB; // 1
        break;
    case 2:
        newtio.c_cflag |= CSTOPB; // 2
        break;
    default:
        newtio.c_cflag &= ~CSTOPB;
        break;
    }
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;
    newtio.c_cflag |= (CLOCAL | CREAD);
    newtio.c_oflag |= OPOST;
    newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
    cfsetispeed(&newtio, baudrate);
    cfsetospeed(&newtio, baudrate);
    tcflush(fd, TCIFLUSH);
    if (tcsetattr(fd, TCSANOW, &newtio) != 0)
    {
        perror("SetupSerial 3");
        return -1;
    }
    printf("Setup Serial Succeed!\n");
    return 0;
}

void clearport(int fd) // 如果出现数据与规约不符合，可以调用这个函数来刷新串口读写数据
{
    tcflush(fd, TCIOFLUSH);
}
#include "type_assemble.hpp"

// void *route(int arg)
// {
//     Init(card_vector);
//     int fd;
//     // int value=(int)arg;
//     fd = OpenPort(arg, 1000000, '8', '1', 'n', fd);
//     set_port_normal(fd);
//     printf("fd:%d fd opened successful!!!!!!!!!!!!!!!!!!!!!!!!\n", fd);
//     while (1)
//     {
//         printf("we are collecting serials data from fd%d, average 500ms one round.--------------------------------------------------------\n", fd);
//         for (int i = 0; i < card_vector.size(); i++)
//         {

//             int card_addr = card_vector[i].add_;
//             int card_type = card_vector[i].type_;

//             int rc, ret, mode, tty_id, parity;
//             char rbuf[50];
//             char wbuf[50];

//             unsigned long controlbits = 0;
//             for (int j = 0; j < 50; j++)
//             {
//                 wbuf[j] = card_vector[i].wbuf_[j];
//             }

//             struct timespec start;
//             struct timespec end;
//             tcflush(fd, TCIOFLUSH); // TCIOFLUSH 标志表示同时清空输入和输出缓冲区。
//             set_port_bit9(fd);
//             WritePort(wbuf, 1, fd);
//             set_port_bit8(fd);
//             tcflush(fd, TCIOFLUSH);
//             int write_len = card_vector[i].length_ - 1;
//             // if (Select == 1)
//             //     write_len = 4; // DI
//             // else if (Select == 2)
//             //     write_len = 8; // DO
//             // else if (Select == 3)
//             //     write_len = 20; // AO
//             // else if (Select == 4)
//             //     write_len = 8; // AI
//             WritePort(wbuf + 1, write_len, fd);
//             //  write(fd,wbuf,6);
//             //    usleep(1000);

//             //  sleep(1);
//             //  rc=read(fd,rbuf,6);
//             clock_gettime(CLOCK_MONOTONIC, &start);
//             fd_set fdRead;
//             // int ret;
//             struct timeval aTime;

//             FD_ZERO(&fdRead); // 清空 fdRead 集合
//             FD_SET(fd, &fdRead);
//             int m_DatLen = 0;
//             memset(rbuf, 0, 50);                               // memset 函数是用于将一段内存块的内容设置为指定的值。在你的代码中，它被用于将缓冲区 rbuf 的前 50 个字节的内容设置为 0。
//             aTime.tv_sec = 0;                                  // 秒数
//             aTime.tv_usec = 3000;                              // 微秒数
//             ret = select(fd + 1, &fdRead, NULL, NULL, &aTime); // select 函数是一个用于多路复用的系统调用，用于监视文件描述符的状态变化。在你的代码中，select 函数被用于等待文件描述符集合中的可读事件，并设置了超时时间。   fd + 1：表示要监视的文件描述符的最大值加 1。在这里，fd 是一个文件描述符，通过 fd + 1 可以确保 select 函数正确处理文件描述符的范围。

//             if (ret <= 0)
//             {
//                 printf("return fail %d\n", ret);
//                 usleep(1000000);
//                 continue;
//             }
//             int read_len = 0;
//             if (card_type == 23)
//                 read_len = 10; // DI
//             else if (card_type == 24)
//                 read_len = 6; // DO
//             else if (card_type == 22)
//                 read_len = 6; // AO
//             else if (card_type == 19)
//                 read_len = 22; // AI
//             int ri = read_len;
//             int rj = 0;

//             //    int first = 0;

//             if (ret > 0)
//             {
//                 if (FD_ISSET(fd, &fdRead))
//                 {
//                     // data available, so get it!
//                     while (m_DatLen < read_len)
//                     {
//                         // read 函数的返回值是一个 ssize_t 类型的整数，表示实际读取的字节数。
//                         rj = read(fd, rbuf + m_DatLen, ri); // fd：是要读取数据的文件描述符。rbuf：是存储读取数据的缓冲区的指针。m_DatLen：是缓冲区 rbuf 的偏移位置，表示从偏移位置开始存储读取的数据。i：是要读取的最大字节数。
//                         if (rj == -1)
//                         {
//                             continue;
//                         }
//                         m_DatLen += rj;
//                         ri = read_len - m_DatLen;
//                     }
//                 }
//                 //        clock_gettime(CLOCK_MONOTONIC, &end);
//                 //        int Time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
//                 //        printf("Time:%d\n", Time);
//             }
//             //  rc=read(fd,rbuf,sizeof(rbuf));
//             if (ret > 0)
//             {
//                 char name[2];
//                 if (card_type == 22)
//                 {
//                     strcpy(name, "AO");
//                 }
//                 if (card_type == 19)
//                 {
//                     strcpy(name, "AI");
//                 }
//                 if (card_type == 24)
//                 {
//                     strcpy(name, "DO");
//                 }
//                 if (card_type == 23)
//                 {
//                     strcpy(name, "DI");
//                 }
//                 printf("i am thread%d ,sending data to %s,which located in %d:", fd, &name, card_addr);
//                 for (int oi = 0; oi < write_len + 1; oi++)
//                     printf("%x ", wbuf[oi]);
//                 printf("\n");
//                 printf("i am thread%d,reading data from %s,which located in %d:", fd, &name, card_addr);
//                 for (int oi = 0; oi < read_len; oi++)
//                     printf("%x ", rbuf[oi]);
//                 printf("\n");
//                 // printf("done successful and we wait 500ms!");
//             }
//         }
//         usleep(500000);
//     }
//     close(fd);
// }
// void *route(int arg)
// {
//     Init(card_vector);
//     int fd;
//     // int value=(int)arg;
//     fd = OpenPort(arg, 1000000, '8', '1', 'n', fd);
//     set_port_normal(fd);
//     printf("fd:%d fd opened successful!!!!!!!!!!!!!!!!!!!!!!!!\n", fd);
//     while (1)
//     {
//         printf("we are collecting serials data from fd%d, average 500ms one round.--------------------------------------------------------\n", fd);
//         for (int i = 0; i < card_vector.size(); i++)
//         {

//             int card_addr = card_vector[i].add_;
//             int card_type = card_vector[i].type_;

//             int rc, ret, mode, tty_id, parity;
//             char rbuf[50];
//             char wbuf[50];

//             unsigned long controlbits = 0;
//             for (int j = 0; j < 50; j++)
//             {
//                 wbuf[j] = card_vector[i].wbuf_[j];
//             }

//             struct timespec start;
//             struct timespec end;
//             tcflush(fd, TCIOFLUSH); // TCIOFLUSH 标志表示同时清空输入和输出缓冲区。
//             set_port_bit9(fd);
//             WritePort(wbuf, 1, fd);
//             set_port_bit8(fd);
//             tcflush(fd, TCIOFLUSH);
//             int write_len = card_vector[i].length_ - 1;
//             // if (Select == 1)
//             //     write_len = 4; // DI
//             // else if (Select == 2)
//             //     write_len = 8; // DO
//             // else if (Select == 3)
//             //     write_len = 20; // AO
//             // else if (Select == 4)
//             //     write_len = 8; // AI
//             WritePort(wbuf + 1, write_len, fd);
//             //  write(fd,wbuf,6);
//             //    usleep(1000);

//             //  sleep(1);
//             //  rc=read(fd,rbuf,6);
//             clock_gettime(CLOCK_MONOTONIC, &start);
//             fd_set fdRead;
//             // int ret;
//             struct timeval aTime;

//             FD_ZERO(&fdRead); // 清空 fdRead 集合
//             FD_SET(fd, &fdRead);
//             int m_DatLen = 0;
//             memset(rbuf, 0, 50);                               // memset 函数是用于将一段内存块的内容设置为指定的值。在你的代码中，它被用于将缓冲区 rbuf 的前 50 个字节的内容设置为 0。
//             aTime.tv_sec = 0;                                  // 秒数
//             aTime.tv_usec = 3000;                              // 微秒数
//             ret = select(fd + 1, &fdRead, NULL, NULL, &aTime); // select 函数是一个用于多路复用的系统调用，用于监视文件描述符的状态变化。在你的代码中，select 函数被用于等待文件描述符集合中的可读事件，并设置了超时时间。   fd + 1：表示要监视的文件描述符的最大值加 1。在这里，fd 是一个文件描述符，通过 fd + 1 可以确保 select 函数正确处理文件描述符的范围。

//             if (ret <= 0)
//             {
//                 printf("return fail %d\n", ret);
//                 usleep(1000000);
//                 continue;
//             }
//             int read_len = 0;
//             if (card_type == 23)
//                 read_len = 10; // DI
//             else if (card_type == 24)
//                 read_len = 6; // DO
//             else if (card_type == 22)
//                 read_len = 6; // AO
//             else if (card_type == 19)
//                 read_len = 22; // AI
//             int ri = read_len;
//             int rj = 0;

//             //    int first = 0;

//             if (ret > 0)
//             {
//                 if (FD_ISSET(fd, &fdRead))
//                 {
//                     // data available, so get it!
//                     while (m_DatLen < read_len)
//                     {
//                         // read 函数的返回值是一个 ssize_t 类型的整数，表示实际读取的字节数。
//                         rj = read(fd, rbuf + m_DatLen, ri); // fd：是要读取数据的文件描述符。rbuf：是存储读取数据的缓冲区的指针。m_DatLen：是缓冲区 rbuf 的偏移位置，表示从偏移位置开始存储读取的数据。i：是要读取的最大字节数。
//                         if (rj == -1)
//                         {
//                             continue;
//                         }
//                         m_DatLen += rj;
//                         ri = read_len - m_DatLen;
//                     }
//                 }
//                 //        clock_gettime(CLOCK_MONOTONIC, &end);
//                 //        int Time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
//                 //        printf("Time:%d\n", Time);
//             }
//             //  rc=read(fd,rbuf,sizeof(rbuf));
//             if (ret > 0)
//             {
//                 char name[2];
//                 if (card_type == 22)
//                 {
//                     strcpy(name, "AO");
//                 }
//                 if (card_type == 19)
//                 {
//                     strcpy(name, "AI");
//                 }
//                 if (card_type == 24)
//                 {
//                     strcpy(name, "DO");
//                 }
//                 if (card_type == 23)
//                 {
//                     strcpy(name, "DI");
//                 }
//                 printf("i am thread%d ,sending data to %s,which located in %d:", fd, &name, card_addr);
//                 for (int oi = 0; oi < write_len + 1; oi++)
//                     printf("%x ", wbuf[oi]);
//                 printf("\n");
//                 printf("i am thread%d,reading data from %s,which located in %d:", fd, &name, card_addr);
//                 for (int oi = 0; oi < read_len; oi++)
//                     printf("%x ", rbuf[oi]);
//                 printf("\n");
//                 // printf("done successful and we wait 500ms!");
//             }
//         }
//         usleep(500000);
//     }
//     close(fd);
// };
struct consumer_select
{
    BlockQueue<card> *BQ;
    int fd_;
};
void *consumer(void *args)
{
    consumer_select *consumer_arg = static_cast<consumer_select *>(args);

    BlockQueue<card> *bq = consumer_arg->BQ;
    int portnum = consumer_arg->fd_;

    int fd;
    // int value=(int)arg;
    fd = OpenPort(portnum, 1000000, '8', '1', 'n', fd);
    set_port_normal(fd);
    printf("fd:%d fd opened successful!!!!!!!!!!!!!!!!!!!!!!!!\n", fd);
    while (1)
    {
        printf("We are tring to collect serials data from fd%d,Max 3000 usec wating in one round.--------------------------------------------------------\n", fd);
        card tmp_card;
        bq->pop(&tmp_card);

        int card_addr = tmp_card.add_;
        int card_type = tmp_card.type_;

        int rc, ret, mode, tty_id, parity;
        char rbuf[50];
        char wbuf[50];

        unsigned long controlbits = 0;
        for (int j = 0; j < 50; j++)
        {
            wbuf[j] = tmp_card.wbuf_[j];
        }

        struct timespec start;
        struct timespec end;
        tcflush(fd, TCIOFLUSH); // TCIOFLUSH 标志表示同时清空输入和输出缓冲区。
        set_port_bit9(fd);
        WritePort(wbuf, 1, fd);
        set_port_bit8(fd);
        tcflush(fd, TCIOFLUSH);
        int write_len = tmp_card.length_ - 1;

        WritePort(wbuf + 1, write_len, fd);
        //  write(fd,wbuf,6);
        //    usleep(1000);

        //  sleep(1);
        //  rc=read(fd,rbuf,6);
        clock_gettime(CLOCK_MONOTONIC, &start);
        fd_set fdRead;
        // int ret;
        struct timeval aTime;

        FD_ZERO(&fdRead); // 清空 fdRead 集合
        FD_SET(fd, &fdRead);
        int m_DatLen = 0;
        memset(rbuf, 0, 50);                               // memset 函数是用于将一段内存块的内容设置为指定的值。在你的代码中，它被用于将缓冲区 rbuf 的前 50 个字节的内容设置为 0。
        aTime.tv_sec = 0;                                  // 秒数
        aTime.tv_usec = 3000;                              // 微秒数
        ret = select(fd + 1, &fdRead, NULL, NULL,&aTime); // select 函数是一个用于多路复用的系统调用，用于监视文件描述符的状态变化。在你的代码中，select 函数被用于等待文件描述符集合中的可读事件，并设置了超时时间。   fd + 1：表示要监视的文件描述符的最大值加 1。在这里，fd 是一个文件描述符，通过 fd + 1 可以确保 select 函数正确处理文件描述符的范围。

        if (ret <= 0)
        {
            printf("return fail sleep 0.1s%d\n", ret);
            usleep(100000);
            continue;
        }
        int read_len = 0;
        if (card_type == 23)
            read_len = 10; // DI
        else if (card_type == 24)
            read_len = 6; // DO
        else if (card_type == 22)
            read_len = 6; // AO
        else if (card_type == 19)
            read_len = 22; // AI
        int ri = read_len;
        int rj = 0;

        //    int first = 0;

        if (ret > 0)
        {
            if (FD_ISSET(fd, &fdRead))
            {
                // data available, so get it!
                while (m_DatLen < read_len)
                {
                    // read 函数的返回值是一个 ssize_t 类型的整数，表示实际读取的字节数。
                    rj = read(fd, rbuf + m_DatLen, ri); // fd：是要读取数据的文件描述符。rbuf：是存储读取数据的缓冲区的指针。m_DatLen：是缓冲区 rbuf 的偏移位置，表示从偏移位置开始存储读取的数据。i：是要读取的最大字节数。
                    if (rj == -1)
                    {
                        continue;
                    }
                    m_DatLen += rj;
                    ri = read_len - m_DatLen;
                }
            }
            //        clock_gettime(CLOCK_MONOTONIC, &end);
            //        int Time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
            //        printf("Time:%d\n", Time);
        }
        //  rc=read(fd,rbuf,sizeof(rbuf));
        if (ret > 0)
        {
            char name[2];
            if (card_type == 22)
            {
                strcpy(name, "AO");
            }
            if (card_type == 19)
            {
                strcpy(name, "AI");
            }
            if (card_type == 24)
            {
                strcpy(name, "DO");
            }
            if (card_type == 23)
            {
                strcpy(name, "DI");
            }
            printf("i am thread%d ,sending data to %s,which located in %d,sending content:%s\n", fd, &name, card_addr,wbuf);
            // for (int oi = 0; oi < write_len + 1; oi++)
            //     printf("%x ", wbuf[oi]);
            // printf("\n");
            printf("i am thread%d,reading data from %s,which located in %d,reading content:%s\n", fd, &name, card_addr,rbuf);
            // for (int oi = 0; oi < read_len; oi++)
            //     printf("%x ", rbuf[oi]);
            // printf("\n");
            printf("Done successful ,and in this round,it takes Microseconds: %ld\n",aTime.tv_usec);
        }

        //usleep(500);
    }
    close(fd);
}

void *productor(void *arg)
{
    BlockQueue<card> *bq = static_cast<BlockQueue<card> *>(arg);
    Init(card_vector);
    while (true)
    {
        for (int i = 0; i < card_vector.size(); i++)
        {
            bq->push(card_vector[i]);
        }
    }
}

int main()
{
    pthread_t t1, t2, t3, p;
    BlockQueue<card> *bq = new BlockQueue<card>();

    consumer_select consumer5_arg;
    consumer5_arg.BQ = bq;
    consumer5_arg.fd_ = 5;

    consumer_select consumer6_arg;
    consumer6_arg.BQ = bq;
    consumer6_arg.fd_ = 6;

    // consumer_select consumer7_arg;
    // consumer7_arg.BQ = bq;
    // consumer7_arg.fd_ = 7;

    pthread_create(&t1, NULL, consumer, (void*)&consumer5_arg);
    pthread_create(&t2, NULL, consumer, (void *)&consumer6_arg);
    // pthread_create(&t3, NULL, consumer, (void *)&consumer7_arg);

    pthread_create(&p, nullptr, productor, bq);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    // pthread_join(t3, NULL);
    pthread_join(p, nullptr);
}
